package com.caishi.lkx.user.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.caishi.lkx.common.BaseApi;
import com.caishi.lkx.common.fliter.TokenFilter;
import com.caishi.lkx.common.ienum.DeviceType;
import com.caishi.lkx.common.role.Role;
import com.caishi.lkx.common.role.Roles;
import com.caishi.lkx.common.util.SmsUtilService;
import com.caishi.lkx.user.ienum.type.UserAccountType;
import com.caishi.lkx.user.model.IUserModel;
import com.caishi.lkx.user.model.LoginInfoModel;
import com.caishi.lkx.user.model.UserModel;
import com.caishi.lkx.user.service.ILoginInfoService;
import com.caishi.lkx.user.service.impl.UserServiceImpl;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.impl.BaseEntity;
import com.zzw.common.exception.BizException;
import com.zzw.common.exception.BizRuntimeException;

import com.caishi.lkx.user.UserResultCode;

import com.caishi.lkx.user.login.LoginService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author by keray
 * date:2021/6/5 10:40 上午
 */
@RestController
@RequestMapping("/user/cu/user")
@Tag(name = "用户登录信息相关")
public class UserLoginApi extends BaseApi {

    @Resource
    private SmsUtilService smsUtilService;

    @Resource
    private UserServiceImpl userService;

    @Resource
    private ILoginInfoService loginInfoService;

    @Resource
    private TokenFilter tokenFilter;


    @Roles({Role.admin})
    @PostMapping("/change/password-admin/{id}")
    public void changeUserPasswordByAdmin(@PathVariable String id, @RequestParam String newPassword) {
        loginInfoService.updatePassword(id, UserAccountType.username, newPassword);
        loginInfoService.updatePassword(id, UserAccountType.group, newPassword);
    }


    @Operation(summary = "获取用户的绑定信息", description = "返回当前用户类型下 0000 0000   -> 0000 机构登录 微信登录 手机号登录 用户名登录")
    @GetMapping("/user-bind-status")
    public int userBindStatus() {
        return loginInfoService.getUserHaveLogin(userContext.currentUserId());
    }

    @Operation(summary = "校验手机号是否可以绑定")
    @Parameters({@Parameter(name = "mobile", description = "需要绑定的手机号", required = true), @Parameter(name = "oldMobile", description = "用户现有的手机号"),})
    @GetMapping("/phone-have-use")
    public Boolean phoneHaveUse(@RequestParam String mobile, String oldMobile) {
        return !userService.mobileExits(mobile, oldMobile);
    }


    @Operation(summary = "用户绑定手机账号")
    @Parameters({@Parameter(name = "mobile", description = "需要绑定的手机号", required = true), @Parameter(name = "code", description = "验证码", required = true),})
    @PostMapping("/bind-mobile")
    public UserModel bindMobile(@RequestParam String mobile, @RequestParam String code, HttpServletRequest request, HttpServletResponse response) throws BizException {
        if (!smsUtilService.checkCode(mobile, code, SmsUtilService.SmsCodeType.bindPhone)) {
            throw new BizException(UserResultCode.smsCodeError);
        }
        UserModel userModel = userService.getById(userContext.currentUserId());
        if (StrUtil.isNotBlank(userModel.getMobile())) {
            throw new BizException(UserResultCode.userHaveBindMobile);
        }
        return bindMobile(userModel, mobile, request, response);
    }

    private UserModel bindMobile(UserModel userModel, String mobile, HttpServletRequest request, HttpServletResponse response) throws BizException {
        var user = userService.bindPhone(userModel, mobile);
        if (!user.getId().equals(userContext.currentUserId())) {
            // 更换了用户 刷新token
            var token = tokenFilter.resetToken(user.getId(), request);
            var device = userContext.currentTokenData().getDevice();
            if (device == DeviceType.pc || device == DeviceType.admin || device == DeviceType.h5) {
                tokenFilter.responseSetToken(device, response, token, false);
                tokenFilter.responseSetUserInfo(user, device, response);
            } else {
                user.setToken(token);
            }
        }
        return user;
    }


    @Operation(summary = "更换绑定手机号")
    @Parameters({@Parameter(name = "phone", description = "需要绑定的手机号", required = true), @Parameter(name = "code", description = "验证码", required = true),})
    @PostMapping("/reset-bind-mobile")
    @Transactional(rollbackFor = RuntimeException.class)
    public void resetBindMobile(@RequestParam String phone, @RequestParam String code) throws BizException {
        if (!smsUtilService.checkCode(phone, code, SmsUtilService.SmsCodeType.resetBindPhone)) {
            throw new BizException(UserResultCode.smsCodeError);
        }
        UserModel userModel = userService.getById(userContext.currentUserId());
        if (phone.equals(userModel.getMobile())) {
            throw new BizRuntimeException("手机号未更换");
        }
        if (userService.mobileExits(phone, userModel.getMobile())) {
            throw new BizException(UserResultCode.mobileHaveBind);
        }
        userService.update(null, Wrappers.<UserModel>lambdaUpdate().set(IUserModel::getMobile, phone).eq(BaseEntity::getId, userModel.getId()));
        List<LoginInfoModel> loginInfoModels = loginInfoService.selectUserLoginInfo(userContext.currentUserId());
        if (CollUtil.isEmpty(loginInfoModels)) {
            throw new BizRuntimeException(UserResultCode.accountException);
        }
        List<String> ids = loginInfoModels.stream().filter(v -> v.getAccount().equals(userModel.getMobile())).map(BaseEntity::getId).collect(Collectors.toList());
        if (null == ids || ids.isEmpty()) {
            List<String> list = loginInfoModels.stream().filter(f -> f.getLoginType().equals(UserAccountType.phone)).map(LoginInfoModel::getId).toList();
            if (list.isEmpty()) {
                LoginInfoModel loginInfoModel = new LoginInfoModel();
                loginInfoModel.setLoginType(UserAccountType.phone);
                loginInfoModel.setUserId(userModel.getId());
                loginInfoModel.setAccount(phone);
                loginInfoService.insert(loginInfoModel);

            } else {
                loginInfoService.update(null, Wrappers.<LoginInfoModel>lambdaUpdate().set(LoginInfoModel::getAccount, phone).in(BaseEntity::getId, list));
            }

        } else {
            loginInfoService.update(null, Wrappers.<LoginInfoModel>lambdaUpdate().set(LoginInfoModel::getAccount, phone).in(BaseEntity::getId, ids));
        }
    }


    @Operation(summary = "根据原密码修改密码")
    @PutMapping("/pass-update")
    public void passUpdate(@RequestParam String oldPass, @RequestParam String newPass) throws BizException {
        String userId = userContext.currentUserId();
        loginInfoService.updateUserUsernameAndPasswordLoginInfo(userId, newPass, oldPass);
    }

    @Operation(summary = "用户设置账号密码登录的密码")
    @PostMapping("/add-username-login")
    public void addUsernameLogin(@RequestParam String password) {
        String userId = userContext.currentUserId();
        loginInfoService.userAddNewLogin(userService.getUserMobileById(userId), LoginService.passwordEncryption(password), UserAccountType.username, userId);
    }


    @Operation(summary = "操作员新增账号密码登录方式")
    @PostMapping("/put-username-login")
    public void addUsernameLoginForPassword(@RequestParam String userId, @RequestParam String username, @RequestParam String password) {
        loginInfoService.userAddNewLogin(LoginService.passwordEncryption(username), LoginService.passwordEncryption(password), UserAccountType.username, userId);
    }

    /**
     * ========================================================不需要登录接口===================================================================================
     */

    @Operation(summary = "校验用户名登录方式用户名是否存在")
    @Parameters({@Parameter(name = "username", required = true), @Parameter(name = "oldUsername", description = "排除的用户名，比如用户现在的用户名")})
    @GetMapping("/username-check/{username}")
    @Roles
    public Boolean usernameExits(@PathVariable String username, String oldUsername) {
        return loginInfoService.checkUsernameExits(username, oldUsername);
    }

    @Operation(summary = "校验手机号是否注册")
    @Parameters({@Parameter(name = "mobile", required = true), @Parameter(name = "oldMobile", description = "排除的手机号，比如现在用户绑定的手机号"), @Parameter(name = "userType", description = "用户类型 同一个手机号一种用户类型只能注册一次，一个手机号可以注册多种用户类型", example = "member")})
    @GetMapping("/mobile-check/{mobile}")
    @Roles
    public Boolean mobileExits(@PathVariable String mobile, String oldMobile) {
        return userService.mobileExits(mobile, oldMobile);
    }

}
